@@ -26,12 +26,29 @@ module LiquidInterpolatable |
||
26 | 26 |
end |
27 | 27 |
|
28 | 28 |
require 'uri' |
29 |
- # Percent encoding for URI conforming to RFC 3986. |
|
30 |
- # Ref: http://tools.ietf.org/html/rfc3986#page-12 |
|
31 | 29 |
module Filters |
30 |
+ # Percent encoding for URI conforming to RFC 3986. |
|
31 |
+ # Ref: http://tools.ietf.org/html/rfc3986#page-12 |
|
32 | 32 |
def uri_escape(string) |
33 | 33 |
CGI::escape string |
34 | 34 |
end |
35 |
+ |
|
36 |
+ # Escape a string for use in XPath expression |
|
37 |
+ def to_xpath(string) |
|
38 |
+ subs = string.scan(/\G(?:\A\z|[^"]+|[^']+)/).map { |x| |
|
39 |
+ case x |
|
40 |
+ when /"/ |
|
41 |
+ %Q{'#{x}'} |
|
42 |
+ else |
|
43 |
+ %Q{"#{x}"} |
|
44 |
+ end |
|
45 |
+ } |
|
46 |
+ if subs.size == 1 |
|
47 |
+ subs.first |
|
48 |
+ else |
|
49 |
+ 'concat(' << subs.join(', ') << ')' |
|
50 |
+ end |
|
51 |
+ end |
|
35 | 52 |
end |
36 | 53 |
Liquid::Template.register_filter(LiquidInterpolatable::Filters) |
37 | 54 |
|
@@ -1,4 +1,5 @@ |
||
1 | 1 |
require 'spec_helper' |
2 |
+require 'nokogiri' |
|
2 | 3 |
|
3 | 4 |
describe LiquidInterpolatable::Filters do |
4 | 5 |
before do |
@@ -12,4 +13,21 @@ describe LiquidInterpolatable::Filters do |
||
12 | 13 |
@filter.uri_escape('abc:/?=').should == 'abc%3A%2F%3F%3D' |
13 | 14 |
end |
14 | 15 |
end |
16 |
+ |
|
17 |
+ describe 'to_xpath' do |
|
18 |
+ before do |
|
19 |
+ def @filter.to_xpath_roundtrip(string) |
|
20 |
+ Nokogiri::XML('').xpath(to_xpath(string)) |
|
21 |
+ end |
|
22 |
+ end |
|
23 |
+ |
|
24 |
+ it 'should escape a string for use in XPath expression' do |
|
25 |
+ [ |
|
26 |
+ %q{abc}.freeze, |
|
27 |
+ %q{'a"bc'dfa""fds''fa}.freeze, |
|
28 |
+ ].each { |string| |
|
29 |
+ @filter.to_xpath_roundtrip(string).should == string |
|
30 |
+ } |
|
31 |
+ end |
|
32 |
+ end |
|
15 | 33 |
end |
@@ -471,7 +471,7 @@ fire: hot |
||
471 | 471 |
|
472 | 472 |
lambda { |
473 | 473 |
@valid_options['extract']['site_title'] = { |
474 |
- 'css' => "#comic img", 'value' => "'{{title}}'" |
|
474 |
+ 'css' => "#comic img", 'value' => "{{title | to_xpath }}" |
|
475 | 475 |
} |
476 | 476 |
@checker.options = @valid_options |
477 | 477 |
@checker.receive([@event]) |